package com.javasm.commons.config;

import com.javasm.entity.JINXIAOEntity.SysTasks;
import com.javasm.service.JINXIAOService.SysTasksService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.task.TaskSchedulingProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.CronTask;
import org.springframework.scheduling.config.ScheduledTask;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;

import javax.annotation.Resource;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
//在启动类中 @EnableScheduling //启用定时任务 作用：1. 识别bean对象中@Scheduled注解的方法
//                                             2. 对SchedulingConfigurer类型的bean对象，启动后直接执行configureTasks方法.
@Configuration
@Slf4j
public class TaskConfigurer implements SchedulingConfigurer {// SchedulingConfigurer注册容器后的bean对象
    //注入service 获取后台数据
    @Resource
    private SysTasksService tasksService;
    //获取当前定时任务   的状态放入 Map集合中  成员变量
    private Map<String,ScheduledTask> runningTask  =new HashMap<>();
    //调度任务注册器 来管理任务
    private ScheduledTaskRegistrar taskRegistrar;
    //获取application.yml文件中线程池的大小
    @Resource
    private TaskSchedulingProperties taskSchedulingProperties;

    //使用调度任务注册器对象来管理任务.
    //在此方法中,查询数据库表所有running状态的任务,启动这些任务.
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        //扩容线程池的大小  达到并行任务（默认的是串行任务，单线程任务），如果数据库配置的是类名加方法名，可以直接在方法中添加注解@Async,无须在此处手动扩容线程池
        taskRegistrar.setScheduler(Executors.newScheduledThreadPool(taskSchedulingProperties.getPool().getSize()));

        this.taskRegistrar=taskRegistrar;
        List<SysTasks> running = tasksService.listRunning();
        log.info("当前正在运行的定时任务有：{}",running);
        for (SysTasks task : running) {
            start(task);
        }
    }

    //开启定时任务
    public void start(SysTasks task) {
        String id = task.getId();//1
        String tclz = task.getTaskClass();//com.javasm.task.WeatherTask
        String tcron = task.getTaskCron();//0/5 * * * * ?
        Runnable runnable = createRunnable(tclz);
        if(runnable==null)return;
        CronTask cronTask = new CronTask(runnable,tcron); //反射定时任务实例化
        ScheduledTask scheduledTask = taskRegistrar.scheduleCronTask(cronTask); // 被调度的任务对象
        runningTask.put(id,scheduledTask); //任务创建完成后，放入成员变量map集合中，key是任务id
    }
  //关闭定时任务
    public void stop(String id) {
        ScheduledTask scheduledTask = runningTask.get(id);
        if(scheduledTask!=null){
            scheduledTask.cancel();
            runningTask.remove(id); //从map集合中移除

        }
    }
    //反射实例化  对象       实例继承的是Runnable对象
    public Runnable createRunnable(String clzName){  //类名反射实例化
        try {
            //clzName ==  "com.javasm.task.WeatherTask"
            Class<?> clz = Class.forName(clzName);//加载类对象
            //得到构造器  得到类中的无参构造对象
            Constructor<?> constructor = clz.getConstructor();//得到类中的无参构造对象
            //newInstance()方法实际上就是使用对应类的无参构造方法来创建该类的实例  反射得到 new WeatherTask()
            Object o = constructor.newInstance();//new WeatherTask();
            return (Runnable)o;
        } catch (Exception e) {
            return null;
        }
    }



}
